package com.dwy2002.order.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.dwy2002.common.Result;
import com.dwy2002.common.exception.EmptyIdException;
import com.dwy2002.enums.NumberEnum;
import com.dwy2002.enums.Status;
import com.dwy2002.order.mapper.OrdersMapper;
import com.dwy2002.order.mapper.PaymentRecordsMapper;
import com.dwy2002.order.service.IOrderStatusLogsService;
import com.dwy2002.order.service.IPaymentRecordsService;
import com.dwy2002.pojo.dto.order.OrderStatusLogsDTO;
import com.dwy2002.pojo.dto.order.RefundStatusEnableRequestDTO;
import com.dwy2002.pojo.po.order.OrderStatusLogs;
import com.dwy2002.pojo.po.order.Orders;
import com.dwy2002.pojo.po.order.PaymentRecords;
import com.dwy2002.pojo.vo.order.PaymentRecordsVO;
import lombok.RequiredArgsConstructor;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.List;
import java.util.stream.Collectors;

import static com.dwy2002.common.Result.*;
import static com.dwy2002.common.utils.Utils.isEmptyOrNull;

/**
 * @author 杜伟毅
 * @version 1.0
 * @since 2025/03/06
 */
@Service
@RequiredArgsConstructor
public class PaymentRecordsServiceImpl extends ServiceImpl<PaymentRecordsMapper, PaymentRecords> implements IPaymentRecordsService {
    private final OrdersMapper ordersMapper;
    private final IOrderStatusLogsService orderStatusLogsService;

    /**
     * 保存支付信息
     *
     * @param orders 订单信息
     * @author 杜伟毅
     * @since 2025/3/14 0014 16:33
     */
    @Override
    public void savePaymentRecord(Orders orders) {
        PaymentRecords paymentRecords = BeanUtil.copyProperties(orders, PaymentRecords.class);
        paymentRecords.setOrderId(orders.getId());
        paymentRecords.setStatus(PaymentRecords.StatusEnum.SUCCESS.getCode());
        paymentRecords.setPayerInfo("测试数据");
        paymentRecords.setAmount(orders.getTotalAmount());
        save(paymentRecords);
    }

    /**
     * 更新单个订单的可退款状态为不可退款
     *
     * @param orderId 订单id
     * @return true：更新成功 false：更新失败
     * @author 杜伟毅
     * @since 2025/3/14 0014 22:41
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean expireRefundStatusByOrder(String orderId) {
        // 获取订单信息
        Orders order = Db.getById(orderId, Orders.class);
        if (ObjectUtils.isEmpty(order)) throw new RuntimeException("订单不存在");

        // 获取支付记录
        PaymentRecords paymentRecord = getById(orderId);
        if (ObjectUtils.isEmpty(paymentRecord)) throw new RuntimeException("支付记录不存在");

        // 状态过滤（已不可退款或已退款）
        if (paymentRecord.getIsRefundable() == NumberEnum.ZERO.getValue()) return false;

        // 计算时间差（精确到小时）
        LocalDateTime now = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
        long hours = Duration.between(order.getCreatedAt(), now).toHours();

        if (hours >= 24) {
            LambdaUpdateWrapper<PaymentRecords> luw = new LambdaUpdateWrapper<>();
            luw.eq(PaymentRecords::getOrderId, orderId)
                    .set(PaymentRecords::getIsRefundable, NumberEnum.ZERO.getValue());
            return update(luw);
        }
        return false;
    }

    /**
     * 批量更新过期订单的可退款状态(定时任务)
     *
     * @author 杜伟毅
     * @since 2025/3/14 0014 22:42
     */
    @Scheduled(cron = "0 0 3 * * ?") // 每天凌晨3点执行
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void batchUpdateRefundStatus() {
        // 查询超过1天的订单ID列表
        LocalDateTime threeDaysAgo = LocalDateTime.now().minusDays(1);
        List<String> orderIds = ordersMapper.selectList(
                        new LambdaQueryWrapper<Orders>()
                                .select(Orders::getId)
                                .lt(Orders::getCreatedAt, threeDaysAgo)
                ).stream()
                .map(Orders::getId)
                .collect(Collectors.toList());

        if (!orderIds.isEmpty()) {
            LambdaUpdateWrapper<PaymentRecords> luw = new LambdaUpdateWrapper<>();
            luw.in(PaymentRecords::getOrderId, orderIds)
                    .set(PaymentRecords::getIsRefundable, NumberEnum.ZERO.getValue());
            // 批量更新支付记录
            update(luw);
        }
    }

    /**
     * 更新单个订单变为可退款
     *
     * @author 杜伟毅
     * @since 2025/3/14 0014 23:08
     */
    @Override
    public Result<Void> enableRefundStatus(RefundStatusEnableRequestDTO dto) {
        if (isEmptyOrNull(dto.getOrderId())) throw new EmptyIdException("enableRefundStatus");
        // 获取订单信息
        Orders order = Db.getById(dto.getOrderId(), Orders.class);
        if (ObjectUtils.isEmpty(order)) return fail(Status.BAD_REQUEST, "订单不存在");

        // 获取支付记录
        PaymentRecords paymentRecord = getById(dto.getOrderId());
        if (ObjectUtils.isEmpty(paymentRecord)) return fail(Status.BAD_REQUEST, "支付记录不存在");

        // 状态过滤（已经是可退款状态）
        if (paymentRecord.getIsRefundable() == NumberEnum.ONE.getValue())
            return fail(Status.BAD_REQUEST, "该订单已经是可退款状态");

        LambdaUpdateWrapper<PaymentRecords> luw = new LambdaUpdateWrapper<>();
        luw.eq(PaymentRecords::getOrderId, dto.getOrderId())
                .set(PaymentRecords::getIsRefundable, NumberEnum.ONE.getValue());
        boolean update = update(luw);

        // 记录状态变更日志
        recordStatusLog(order, paymentRecord, NumberEnum.ONE.getValue(), dto.getRemark());

        return handleResult(update, "修改成功", "修改失败");
    }

    /**
     * 返回该订单是否为不可退款
     *
     * @param id 订单id
     * @author 杜伟毅
     * @since 2025/5/11 0011 16:44
     */
    @Override
    public Result<PaymentRecordsVO> getIsRefundable(String id) {
        if (isEmptyOrNull(id)) throw new EmptyIdException("getIsRefundable");
        LambdaQueryWrapper<PaymentRecords> lqw = new LambdaQueryWrapper<PaymentRecords>().eq(PaymentRecords::getOrderId, id);
        return success(BeanUtil.copyProperties(getOne(lqw), PaymentRecordsVO.class));
    }

    //-----辅助方法----------------------------------------------------------

    /**
     * 记录订单状态变更日志
     *
     * @author 杜伟毅
     * @since 2025/3/15 0015 15:27
     */
    private void recordStatusLog(Orders order, PaymentRecords paymentRecord, Integer newStatus, String remark) {
        OrderStatusLogsDTO logsDTO = new OrderStatusLogsDTO()
                .setOrderId(order.getId())
                .setOldStatus(paymentRecord.getIsRefundable())
                .setNewStatus(newStatus)
                .setOperatorType(OrderStatusLogs.OperatorTypeEnum.ADMIN.getCode())
                .setRemark(remark);
        orderStatusLogsService.recordOrderStatusLog(logsDTO);
    }
}
